<?php defined('SYSPATH') or die('No direct script access.');

/**
 * Flickr Service Driver Library
 * http://www.flickr.com/services/api/
 *
 * $Id: Flickr.php 160 2008-10-27 22:55:51Z alex.aperez $
 *
 * @package		Service Module
 * @author		Alex Sancho
 * @copyright	(c) 2008 Alex Sancho
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *	  notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *	  notice, this list of conditions and the following disclaimer in the
 *	  documentation and/or other materials provided with the distribution.
 * 3. Neither the name of copyright holders nor the names of its
 *	  contributors may be used to endorse or promote products derived
 *	  from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.	IN NO EVENT SHALL COPYRIGHT HOLDERS OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

class Service_Flickr_Driver extends Service_Driver 
{
	protected $api_url	= 'flickr.com/services/rest/?';
	protected $api_key	= null;
	protected $secret	= null;
	protected $response = null;

	/**
	 *	__construct
	 * 
	 * @param array $config
	 * @return void
	 * @access public
	 * 
	 */
	public function __construct($config = array())
	{
		$config += Kohana::config('service.flickr');

		foreach($config as $key => $val)
			$this->$key = $val;
	}

	/**
	 * activity_user_comments
	 * 
	 * @param integer $per_page
	 * @param integer $page
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function activity_user_comments($per_page = null, $page = null)
	{
		$params = array
		(
			'per_page'	=> $per_page,
			'page'		=> $page
		);

		$this->auth('read')->api_call('flickr.activity.userComments', $params);
		return $this->response->items;
	}

	/**
	 * activity_user_photos
	 * 
	 * @param string $timeframe
	 * @param integer $per_page
	 * @param integer $page
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function activity_user_photos($timeframe = null, $per_page = null, $page = null)
	{
		$params = array
		(
			'timeframe' => $timeframe,
			'per_page'	=> $per_page,
			'page'		=> $page
		);

		$this->auth('read')->api_call('flickr.activity.userPhotos', $params);
		return $this->response->items;
	}

	/**
	 * blogs_get_list
	 * 
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function blogs_get_list()
	{
		$this->auth('read')->api_call('flickr.blogs.getList');
		return $this->response->blogs;
	}

	/**
	 * blog_post_photo
	 * 
	 * @param integer $blog_id
	 * @param integer $photo_id
	 * @param string $title
	 * @param string $description
	 * @param string $blog_password
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function blogs_post_photo($blog_id, $photo_id, $title, $description, $blog_password = null)
	{
		$params = array
		(
			'blog_id'		=> $blog_id,
			'photo_id'		=> $photo_id,
			'title'			=> $title,
			'description'	=> $description,
			'blog_password' => $blog_password
		);

		$this->auth('write')->api_call('flickr.blogs.postPhoto', $params, true);
		return $this->response;
	}

	/**
	 * contacts_get_list
	 * 
	 * @param string $filter
	 * @param integer $page
	 * @param integer $per_page
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function contacts_get_list($filter = null, $page = null, $per_page = null)
	{
		$params = array
		(
			'filter'	=> $filter,
			'page'		=> $page,
			'per_page'	=> $per_page
		);

		$this->auth('read')->api_call('flickr.contacts.getList', $params);
		return $this->response->contacts;
	}

	/**
	 * contacts_get_public_list
	 * 
	 * @param string $user_id
	 * @param integer $page
	 * @param integer $per_page
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function contacts_get_public_list($user_id, $page = null, $per_page = null)
	{
		$params = array
		(
			'user_id'	=> $user_id,
			'page'		=> $page,
			'per_page'	=> $per_page
		);

		$this->api_call('flickr.contacts.getPublicList', $params);
		return $this->response->contacts;
	}

	/**
	 * favorites_add
	 * 
	 * @param integer $id
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function favorites_add($id)
	{
		$this->auth('write')->api_call('flickr.favorites.add', array('photo_id' => $id), true);
		return $this->response;
	}

	/**
	 * favorites_get_public_list
	 * 
	 * @param string $user_id
	 * @param string $extras
	 * @param integer $per_page
	 * @param integer $page
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function favorites_get_public_list($user_id, $extras = null, $per_page = null, $page = null)
	{
		$params = array
		(
			'user_id'	=> $user_id,
			'extras'	=> self::implode($extras),
			'per_page'	=> $per_page,
			'page'		=> $page
		);

		$this->api_call('flickr.favorites.getPublicList', $params);
		return $this->response->photos;
	}

	/**
	 * favorites_remove
	 * 
	 * @param integer $id
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function favorites_remove($id)
	{
		$this->auth('write')->api_call('flickr.favorites.remove', array('photo_id' => $id), true);
		return $this->response;
	}

	/**
	 * favorites_get_list
	 * 
	 * @param integer $id
	 * @param string $extras
	 * @param integer $per_page
	 * @param integer $page
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function favorites_get_list($id = null, $extras = null, $per_page = null, $page = null)
	{
		$params = array
		(
			'user_id'	=> $id,
			'extras'	=> self::implode($extras),
			'per_page'	=> $per_page,
			'page'		=> $page
		);

		$this->auth('read')->api_call('flickr.favorites.getList', $params);
		return $this->response->photos;
	}

	/**
	 * groups_browse
	 * 
	 * @param integer $id
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function groups_browse($id = null)
	{
		$this->auth('read')->api_call('flickr.groups.browse', array('cat_id' => $id));
		return $this->response->category;
	}

	/**
	 * groups_get_info
	 * 
	 * @param integer $id
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function groups_get_info($id)
	{
		$this->api_call('flickr.groups.getInfo', array('group_id' => $id));
		return $this->response->group;
	}

	/**
	 * groups_search
	 * 
	 * @param string $text
	 * @param integer $per_page
	 * @param integer $page
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function groups_search($text, $per_page = null, $page = null)
	{
		$params = array
		(
			'text'		=> $text,
			'per_page'	=> $per_page,
			'page'		=> $page
		);

		$this->api_call('flickr.groups.search', $params);
		return $this->response->groups;
	}

	/**
	 * groups_pools_add
	 * 
	 * @param integer $photo_id
	 * @param integer $group_id
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function groups_pools_add($photo_id, $group_id)
	{
		$params = array
		(
			'photo_id' => $photo_id,
			'group_id' => $group_id
		);

		$this->auth('write')->api_call('flickr.groups.pools.add', $params, true);
		return $this->response;
	}

	/**
	 * groups_pools_get_context
	 * 
	 * @param integer $photo_id
	 * @param integer $group_id
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function groups_pools_get_context($photo_id, $group_id)
	{
		$params = array
		(
			'photo_id' => $photo_id,
			'group_id' => $group_id
		);

		$this->api_call('flickr.groups.pools.getContext', $params);
		return $this->response;
	}

	/**
	 * groups_pools_get_groups
	 *
	 * @param integer $page
	 * @param integer $per_page
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function groups_pools_get_groups($page = null, $per_page = null)
	{
		$params = array
		(
			'page'		=> $page,
			'per_page'	=> $per_page
		);
		$this->auth('read')->api_call('flickr.groups.pools.getGroups', $params);
		return $this->response->groups;
	}

	/**
	 * groups_pools_get_photos
	 *
	 * @param integer $group_id
	 * @param string $tags
	 * @param string $user_id
	 * @param mixed $extras
	 * @param integer $per_page
	 * @param integer $page
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function groups_pools_get_photos($group_id, $tags = null, $user_id = null, $extras = null, $per_page = null, $page = null)
	{
		$params = array
		(
			'group_id'	=> $group_id,
			'tags'		=> $tags,
			'user_id'	=> $user_id,
			'extras'	=> self::implode($extras),
			'per_page'	=> $per_page,
			'page'		=> $page
		);

		$this->api_call('flickr.groups.pools.getPhotos', $params);
		return $this->response->photos;
	}

	/**
	 * groups_pools_remove
	 *
	 * @param string $photo_id
	 * @param string $group_id
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function groups_pools_remove($photo_id, $group_id)
	{
		$params = array
		(
			'photo_id'	=> $photo_id,
			'group_id'	=> $group_id
		);

		$this->auth('write')->api_call('flickr.groups.pools.remove', $params, true);
		return $this->response;
	}

	/**
	 * interestingness_get_list
	 *
	 * @param integer $date
	 * @param mixed $extras
	 * @param integer $per_page
	 * @param integer $page
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function interestingness_get_list($date = null, $extras = null, $per_page = null, $page = null)
	{
		$params = array
		(
			'date'		=> $date,
			'extras'	=> self::implode($extras),
			'per_page'	=> $per_page,
			'page'		=> $page
		);

		$this->api_call('flickr.interestingness.getList', $params);
		return $this->response->photos;
	}

	/**
	 * people_find_by_email
	 *
	 * @param string $email
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function people_find_by_email($email)
	{
		$this->api_call('flickr.people.findByEmail', array('find_email' => $email));
		return $this->response->user;
	}

	/**
	 * people_find_by_username
	 *
	 * @param string $username
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function people_find_by_username($username)
	{
		$this->api_call('flickr.people.findByUsername', array('username' => $username));
		return $this->response->user;
	}

	/**
	 * people_get_info
	 *
	 * @param string $id
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function people_get_info($id)
	{
		$this->api_call('flickr.people.getInfo', array('user_id' => $id));
		return $this->response->person;
	}

	/**
	 * people_get_public_groups
	 *
	 * @param string $id
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function people_get_public_groups($id)
	{
		$this->api_call('flickr.people.getPublicGroups', array('user_id' => $id));
		return $this->response->groups;
	}

	/**
	 * people_get_public_photos
	 *
	 * @param string $id
	 * @param mixed $extras
	 * @param integer $per_page
	 * @param integer $page
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function people_get_public_photos($id, $extras = null, $per_page = null, $page = null)
	{
		$params = array
		(
			'user_id'	=> $id,
			'extras'	=> self::implode($extras),
			'per_page'	=> $per_page,
			'page'		=> $page
		);

		$this->api_call('flickr.people.getPublicPhotos', $params);
		return $this->response->photos;
	}

	/**
	 * people_get_upload_status
	 *
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function people_get_upload_status()
	{
		$this->auth('read')->api_call('flickr.people.getUploadStatus');
		return $this->response->user;
	}

	/**
	 * photos_add_tags
	 *
	 * @param integer $id
	 * @param mixed $tags
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	function photos_add_tags($id, $tags)
	{
		$params = array
		(
			'photo_id'	=> $id,
			'tags'		=> self::implode($tags, " ")
		);

		$this->auth('write')->api_call('flickr.photos.addTags', $params, true);
		return $this->response;
	}

	/**
	 * photos_delete
	 *
	 * @param integer $id
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_delete($id)
	{
		$this->auth('delete')->api_call('flickr.photos.delete', array('photo_id' => $id), true);
		return $this->response;
	}

	/**
	 * photos_get_all_contexts
	 *
	 * @param integer $id
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_get_all_contexts($id)
	{
		$this->api_call('flickr.photos.getAllContexts', array('photo_id' => $id));
		return $this->response;
	}

	/**
	 * photos_get_contacts_photos
	 *
	 * @param boolean $count
	 * @param boolean $just_friends
	 * @param boolean $single_photo
	 * @param boolean $include_self
	 * @param string $extras
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_get_contacts_photos($count = null, $just_friends = null, $single_photo = null, $include_self = null, $extras = null)
	{
		$params = array
		(
			'count'			=> $count,
			'just_friends'	=> (int) $just_friends,
			'single_photo'	=> (int) $single_photo,
			'include_self'	=> (int) $include_self,
			'extras'		=> $extras
		);

		$this->auth('read')->api_call('flickr.photos.getContactsPhotos', $params);
		return $this->response->photos;
	}

	/**
	 * photos_get_contacts_public_photos
	 *
	 * @param string $id
	 * @param boolean $count
	 * @param boolean $just_friends
	 * @param boolean $single_photo
	 * @param boolean $include_self
	 * @param string $extras
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_get_contacts_public_photos($id, $count = null, $just_friends = null, $single_photo = null, $include_self = null, $extras = null)
	{
		$params = array
		(
			'user_id'		=> $id,
			'count'			=> $count,
			'just_friends'	=> (int) $just_friends,
			'single_photo'	=> (int) $single_photo,
			'include_self'	=> (int) $include_self,
			'extras'		=> $extras
		);

		$this->api_call('flickr.photos.getContactsPublicPhotos', $params);
		return $this->response->photos;
	}

	/**
	 * photos_get_context
	 *
	 * @param integer $id
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_get_context($id)
	{
		$this->api_call('flickr.photos.getContext', array('photo_id' => $id));
		return $this->response;
	}

	/**
	 * photos_get_counts
	 *
	 * @param integer $dates
	 * @param integer $taken_dates
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_get_counts($dates = null, $taken_dates = null)
	{
		$params = array
		(
			'dates'			=> $dates, 
			'taken_dates'	=> $taken_dates
		);

		$this->auth('read')->api_call('flickr.photos.getCounts', $params);
		return $this->response->photocounts;
	}

	/**
	 * photos_get_exif
	 *
	 * @param integer $id
	 * @param string $secret
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_get_exif($id, $secret = null)
	{
		$params = array
		(
			'photo_id'	=> $id,
			'secret'	=> $secret
		);

		$this->api_call('flickr.photos.getExif', $params);
		return $this->response->photo;
	}

	/**
	 * photos_get_favorites
	 *
	 * @param integer $id
	 * @param integer $page
	 * @param integer $per_page
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_get_favorites($id, $page = null, $per_page = null)
	{
		$params = array
		(
			'photo_id'	=> $id,
			'page'		=> $page,
			'per_page'	=> $per_page
		);

		$this->api_call('flickr.photos.getFavorites', $params);
		return $this->response->photo;
	}

	/**
	 * photos_get_info
	 *
	 * @param integer $id
	 * @param string $secret
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_get_info($id, $secret = null)
	{
		$params = array
		(
			'photo_id'	=> $id,
			'secret'	=> $secret
		);

		$this->api_call('flickr.photos.getInfo', $params);
		return $this->response->photo;
	}

	/**
	 * photos_get_not_in_set
	 *
	 * @param integer $min_upload_date
	 * @param integer $max_upload_date
	 * @param integer $min_taken_date
	 * @param integer $max_taken_date
	 * @param integer $privacy_filter
	 * @param mixed $extras
	 * @param integer $per_page
	 * @param integer $page
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_get_not_in_set($min_upload_date = null, $max_upload_date = null, $min_taken_date = null, $max_taken_date = null, $privacy_filter = null, $extras = null, $per_page = null, $page = null)
	{
		$params = array
		(
			'min_upload_date'	=> $min_upload_date,
			'max_upload_date'	=> $max_upload_date,
			'min_taken_date'	=> $min_taken_date,
			'max_taken_date'	=> $max_taken_date,
			'privacy_filter'	=> $privacy_filter,
			'extras'			=> self::implode($extras),
			'per_page'			=> $per_page,
			'page'				=> $page
		);

		$this->auth('read')->api_call('flickr.photos.getNotInSet', $params);
		return $this->response->photos;
	}

	/**
	 * photos_get_perms
	 *
	 * @param integer $id
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_get_perms($id)
	{
		$this->auth('read')->api_call('flickr.photos.getPerms', array('photo_id' => $id));
		return $this->response->perms;
	}

	/**
	 * photos_get_recent
	 *
	 * @param mixed $extras
	 * @param integer $per_page
	 * @param integer $page
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_get_recent($extras = null, $per_page = null, $page = null)
	{
		$params = array
		(
			'extras'	=> self::implode($extras),
			'per_page'	=> $per_page,
			'page'		=> $page
		);

		$this->api_call('flickr.photos.getRecent', $params);
		return $this->response->photo;
	}

	/**
	 * photos_get_sizes
	 *
	 * @param integer $id
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_get_sizes($id)
	{
		$this->api_call('flickr.photos.getSizes', array('photo_id' => $id));
		return $this->response->sizes;
	}

	/**
	 * photos_get_untagged
	 *
	 * @param integer $min_upload_date
	 * @param integer $max_upload_date
	 * @param integer $min_taken_date
	 * @param integer $max_taken_date
	 * @param boolean $privacy_filter
	 * @param string $extras
	 * @param integer $per_page
	 * @param integer $page
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_get_untagged($min_upload_date = null, $max_upload_date = null, $min_taken_date = null, $max_taken_date = null, $privacy_filter = null, $extras = null, $per_page = null, $page = null)
	{
		$params = array
		(
			'min_upload_date'	=> $min_upload_date,
			'max_upload_date'	=> $max_upload_date,
			'min_taken_date'	=> $min_taken_date,
			'max_taken_date'	=> $max_taken_date,
			'privacy_filter'	=> $privacy_filter,
			'extras'			=> self::implode($extras),
			'per_page'			=> $per_page,
			'page'				=> $page
		);

		$this->auth('read')->api_call('flickr.photos.getUntagged', $params);
		return $this->response->photos;
	}

	/**
	 * photos_get_with_geo_data
	 *
	 * @param array $params
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_get_with_geo_data($params = array())
	{
		$this->auth('read')->api_call('flickr.photos.getWithGeoData', $params);
		return $this->response->photos;
	}

	/**
	 * photos_get_without_geo_data
	 *
	 * @param array $params
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_get_without_geo_data($params = array())
	{
		$this->auth('read')->api_call('flickr.photos.getWithoutGeoData', $params);
		return $this->response->photos;
	}

	/**
	 * photos_recently_updated
	 * 
	 * @param integer $min_date
	 * @param mixed $extras
	 * @param integer $per_page
	 * @param integer $page
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_recently_updated($min_date = null, $extras = null, $per_page = null, $page = null)
	{
		$params = array
		(
			'min_date'	=> $min_date,
			'extras'	=> self::implode($extras),
			'per_page'	=> $per_page,
			'page'		=> $page
		);

		$this->auth('read')->api_call('flickr.photos.recentlyUpdated', $params);
		return $this->response->photos;
	}

	/**
	 * photos_remove_tag
	 *
	 * @param integer $id
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_remove_tag($id)
	{
		$this->auth('write')->api_call('flickr.photos.removeTag', array('tag_id' => $id), true);
		return $this->response;
	}

	/**
	 * photos_search
	 *
	 * @param array $params
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_search( array $params)
	{
		$this->api_call('flickr.photos.search', $params);
		return $this->response->photos;
	}

	/**
	 * photos_set_content_type
	 *
	 * @param integer $photo_id
	 * @param integer $content_type
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_set_content_type($photo_id, $content_type)
	{
		$params = array
		(
			'photo_id'		=> $photo_id,
			'content_type'	=> $content_type
		);

		$this->api_call('flickr.photos.setContentType', $params, true);
		return $this->response;
	}

	/**
	 * photos_set_dates
	 *
	 * @param integer $photo_id
	 * @param integer $posted
	 * @param integer $taken
	 * @param integer $granularity
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_set_dates($photo_id, $posted = null, $taken = null, $granularity = null)
	{
		$params = array
		(
			'photo_id'					=> $photo_id,
			'date_posted'				=> $posted,
			'date_taken'				=> $taken,
			'date_taken_granularity'	=> $granularity
		);

		$this->auth('write')->api_call('flickr.photos.setDates', $params, true);
		return $this->response;
	}

	/**
	 * photos_set_meta
	 *
	 * @param integer $photo_id
	 * @param string $title
	 * @param string $description
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_set_meta($photo_id, $title, $description)
	{
		$params = array
		(
			'photo_id'		=> $photo_id,
			'title'			=> $title,
			'description'	=> $description
		);

		$this->auth('write')->api_call('flickr.photos.setMeta', $params, true);
		return $this->response;
	}

	/**
	 * photos_set_perms
	 *
	 * @param integer $photo_id
	 * @param boolean $is_public
	 * @param boolean $is_friend
	 * @param boolean $is_family
	 * @param integer $perm_comment
	 * @param integer $perm_addmeta
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_set_perms($photo_id, $is_public, $is_friend, $is_family, $perm_comment, $perm_addmeta)
	{
		$params = array
		(
			'photo_id'		=> $photo_id,
			'is_public'		=> (int) $is_public,
			'is_friend'		=> (int) $is_friend,
			'is_family'		=> (int) $is_family,
			'perm_comment'	=> $perm_comment,
			'perm_addmeta'	=> $perm_addmeta
		);

		$this->auth('write')->api_call('flickr.photos.setPerms', $params, true);
		return $this->response;
	}

	/**
	 * photos_set_safety_level
	 * 
	 * @param integer $photo_id
	 * @param integer $safety_level
	 * @param boolean $hidden
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function photos_set_safety_level($photo_id, $safety_level, $hidden = null)
	{
		$params = array
		(
			'photo_id'		=> $photo_id,
			'safety_level'	=> $safety_level,
			'hidden'		=> (int) $hidden
		);

		$this->auth('write')->api_call('flickr.photos.setSafetyLevel', $params, true);
		return $this->response;
	}

	/**
	 * photos_set_tags
	 * 
	 * @param integer $photo_id
	 * @param mixed $tags
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function photos_set_tags($photo_id, $tags)
	{
		$params = array
		(
			'photo_id'	=> $photo_id,
			'tags'		=> self::implode($tags, " ")
		);

		$this->auth('write')->api_call('flickr.photos.setTags', $params, true);
		return $this->response;
	}

	/**
	 * photos_comments_add_comment
	 * 
	 * @param integer $photo_id
	 * @param string $text
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function photos_comments_add_comment($photo_id, $text)
	{
		$params = array
		(
			'photo_id'		=> $photo_id,
			'comment_text'	=> $text
		);

		$this->auth('write')->api_call('flickr.photos.comments.addComment', $params, true);
		return $this->response->comment;
	}

	/**
	 * photos_commentes_delete_comment
	 * 
	 * @param integer $comment_id
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function photos_comments_delete_comment($comment_id)
	{
		$this->auth('write')->api_call('flickr.photos.comments.deleteComment', array('comment_id' => $comment_id), true);
		return $this->response;
	}

	/**
	 * photos_comments_edit_comment
	 * 
	 * @param integer $comment_id
	 * @param string $text
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function photos_comments_edit_comment($comment_id, $text)
	{
		$params = array
		(
			'comment_id'	=> $comment_id,
			'comment_text'	=> $text
		);

		$this->auth('write')->api_call('flickr.photos.comments.editComment', $params, true);
		return $this->response;
	}

	/**
	 * photos_comments_get_list
	 * 
	 * @param integer $photo_id
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function photos_comments_get_list($photo_id)
	{
		$this->api_call('flickr.photos.comments.getList', array('photo_id' => $photo_id));
		return $this->response->comments;
	}

	/**
	 * photos_geo_get_location
	 * 
	 * @param integer $photo_id
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function photos_geo_get_location($photo_id)
	{
		$this->api_call('flickr.photos.geo.getLocation', array('photo_id' => $photo_id));
		return $this->response->photo;
	}

	/**
	 * photos_geo_get_perms
	 * 
	 * @param integer $photo_id
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function photos_geo_get_perms($photo_id)
	{
		$this->api_call('flickr.photos.geo.getPerms', array('photo_id' => $photo_id));
		return $this->response->perms;
	}

	/**
	 * photos_geo_remove_location
	 * 
	 * @param integer $photo_id
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function photos_geo_remove_location($photo_id)
	{
		$this->auth('write')->api_call('flickr.photos.geo.removeLocation', array('photo_id' => $photo_id), true);
		return $this->response;
	}

	/**
	 * photos_geo_set_location
	 * 
	 * @param integer $photo_id
	 * @param integer $lat
	 * @param integer $lon
	 * @param integer $accuracy
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function photos_geo_set_location($photo_id, $lat, $lon, $accuracy = null)
	{
		$params = array
		(
			'photo_id'	=> $photo_id,
			'lat'		=> $lat,
			'lon'		=> $lon,
			'accuracy'	=> $accuracy
		);

		$this->auth('write')->api_call('flickr.photos.geo.setLocation', $params, true);
		return $this->response;
	}

	/**
	 * photos_geo_set_perms
	 * 
	 * @param integer $photo_id
	 * @param boolean $is_public
	 * @param boolean $is_contact
	 * @param boolean $is_friend
	 * @param boolean $is_family
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function photos_geo_set_perms($photo_id, $is_public, $is_contact, $is_friend, $is_family)
	{
		$params = array
		(
			'photo_id'		=> $photo_id,
			'is_public'		=> (int) $is_public,
			'is_contact'	=> (int) $is_contact,
			'is_friend'		=> (int) $is_friend,
			'is_family'		=> (int) $is_family
		);

		$this->auth('write')->api_call('flickr.photos.geo.setPerms', $params, true);
		return $this->response;
	}

	/**
	 * photos_licenses_get_info
	 * 
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function photos_licenses_get_info()
	{
		$this->api_call('flickr.photos.licenses.getInfo');
		return $this->response->licenses;
	}

	/**
	 * photos_licenses_set_license
	 * 
	 * @param integer $photo_id
	 * @param integer $license_id 
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function photos_licenses_set_license($photo_id, $license_id)
	{
		$params = array
		(
			'photo_id'		=> $photo_id,
			'license_id'	=> $license_id
		);

		$this->auth('write')->api_call('flickr.photos.licenses.setLicense', $params, true);
		return $this->response;
	}

	/**
	 * photos_notes_add
	 *
	 * @param integer $photo_id
	 * @param integer $note_x
	 * @param integer $note_y
	 * @param integer $note_w
	 * @param integer $note_h
	 * @param string $text
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_notes_add($photo_id, $note_x, $note_y, $note_w, $note_h, $text)
	{
		$params = array
		(
			'photo_id'	=> $photo_id,
			'note_x'	=> $note_x,
			'note_y'	=> $note_y,
			'note_w'	=> $note_w,
			'note_h'	=> $note_h,
			'note_text' => $text
		);

		$this->auth('write')->api_call('flickr.photos.notes.add', $params, true);
		return $this->response->note;
	}

	/**
	 * photos_notes_delete
	 *
	 * @param integer $note_id
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_notes_delete($id)
	{
		$this->auth('write')->api_call('flickr.photos.notes.delete', array('note_id' => $note_id), true);
		return $this->response;
	}

	/**
	 * photos_notes_edit
	 *
	 * @param integer $note_id
	 * @param integer $note_x
	 * @param integer $note_y
	 * @param integer $note_w
	 * @param integer $note_h
	 * @param string $text
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_notes_edit($note_id, $note_x, $note_y, $note_w, $note_h, $text)
	{
		$params = array
		(
			'note_id'	=> $note_id,
			'note_x'	=> $note_x,
			'note_y'	=> $note_y,
			'note_w'	=> $note_w,
			'note_h'	=> $note_h,
			'note_text' => $text
		);

		$this->auth('write')->api_call('flickr.photos.notes.edit', $params, true);
		return $this->response;
	}

	/**
	 * photos_transform_rotate
	 *
	 * @param integer $photo_id
	 * @param integer $degrees
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_transform_rotate($photo_id, $degrees)
	{
		$params = array
		(
			'photo_id'	=> $photo_id,
			'degrees'	=> $degrees
		);

		$this->auth('write')->api_call('flickr.photos.transform.rotate', $params, true);
		return $this->response;
	}

	/**
	 * photos_upload_check_tickets
	 *
	 * @param mixed $tickets
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photos_upload_check_tickets($tickets)
	{
		$this->api_call('flickr.photos.upload.checkTickets', array('tickets' => self::implode($tickets)));
		return $this->response->uploader;
	}

	/**
	 * photosets_add_photo
	 *
	 * @param integer $photoset_id
	 * @param integer $photo_id
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photosets_add_photo($photoset_id, $photo_id)
	{
		$params = array
		(
			'photoset_id'	=> $photoset_id,
			'photo_id'		=> $photo_id
		);

		$this->auth('write')->api_call('flickr.photosets.addPhoto', $params, true);
		return $this->response;
	}

	/**
	 * photosets_create
	 *
	 * @param string $title
	 * @param integer $primary_photo_id
	 * @param string $description
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photosets_create($title, $primary_photo_id, $description = null)
	{
		$params = array
		(
			'title'				=> $title,
			'primary_photo_id'	=> $primary_photo_id,
			'description'		=> $description
		);

		$this->auth('write')->api_call('flickr.photosets.create', $params, true);
		return $this->response->photoset;
	}

	/**
	 * photosets_delete
	 *
	 * @param integere $photoset_id
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photosets_delete($photoset_id)
	{
		$this->auth('write')->api_call('flickr.photosets.delete', array('photoset_id' => $photoset_id), true);
		return $this->response;
	}

	/**
	 * photosets_edit_meta
	 *
	 * @param integer $photoset_id
	 * @param string $title
	 * @param string $description
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photosets_edit_meta($photoset_id, $title, $description = null)
	{
		$params = array
		(
			'photoset_id'	=> $photoset_id,
			'title'			=> $title,
			'description'	=> $description
		);

		$this->auth('write')->api_call('flickr.photosets.editMeta', $params, true);
		return $this->response;
	}

	/**
	 * photosets_edit_photos
	 *
	 * @param integer $photoset_id
	 * @param integer $primary_photo_id
	 * @param mixed $photo_ids
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photosets_edit_photos($photoset_id, $primary_photo_id, $photo_ids)
	{
		$params = array
		(
			'photoset_id'		=> $photoset_id,
			'primary_photo_id'	=> $primary_photo_id,
			'photo_ids'			=> self::implode($photo_ids)
		);

		$this->auth('write')->api_call('flickr.photosets.editPhotos', $params, true);
		return $this->response;
	}

	/**
	 * photosets_get_context
	 *
	 * @param integer $photo_id
	 * @param integer $photoset_id
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photosets_get_context($photo_id, $photoset_id)
	{
		$params = array
		(
			'photo_id'		=> $photo_id,
			'photoset_id'	=> $photoset_id
		);

		$this->api_call('flickr.photosets.getContext', $params);
		return $this->response;
	}

	/**
	 * photosets_get_info
	 *
	 * @param integer $photoset_id
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function photosets_get_info($photoset_id)
	{
		$this->api_call('flickr.photosets.getInfo', array('photoset_id' => $photoset_id));
		return $this->response->photoset;
	}

	/**
	 * photosets_get_list
	 * 
	 * @param string $user_id
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function photosets_get_list($user_id = null)
	{
		$this->api_call('flickr.photosets.getList', array('user_id' => $user_id));
		return $this->response->photosets;
	}

	/**
	 * photosets_get_photos
	 * 
	 * @param integer $id
	 * @param mixed $extras
	 * @param integer $privacy_filter
	 * @param integer $per_page
	 * @param integer $page
	 * @param string $media
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function photosets_get_photos($id, $extras = null, $privacy_filter = null, $per_page = null, $page = null, $media = 'all')
	{
		$params = array
		(
			'photoset_id'		=> $id,
			'extras'			=> self::implode($extras),
			'privacy_filter'	=> $privacy_filter,
			'per_page'			=> $per_page,
			'page'				=> $page,
			'media'				=> $media
		);

		$this->api_call('flickr.photosets.getPhotos', $params, true);
		return $this->response->photoset;
	}

	/**
	 * photosets_order_sets
	 * 
	 * @param mixed $ids
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	function photosets_order_sets($ids)
	{
		$this->auth('write')->api_call('flickr.photosets.orderSets', array('photoset_ids' => self::implode($ids)), true);
		return $this->response;
	}

	/**
	 * photosets_remove_photo
	 * 
	 * @param string $photoset_id
	 * @param string $photo_id
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function photosets_remove_photo($photoset_id, $photo_id)
	{
		$params = array
		(
			'photoset_id'	=> $photoset_id,
			'photo_id'		=> $photo_id
		);

		$this->auth('write')->api_call('flickr.photosets.removePhoto', $params, true);
		return $this->response;
	}

	/**
	 * photosets_comments_add_comment
	 * 
	 * @param integer $photoset_id
	 * @param string $text
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function photosets_comments_add_comment($photoset_id, $text)
	{
		$params = array
		(
			'photoset_id'	=> $photoset_id,
			'comment_text'	=> $text
		);

		$this->auth('write')->api_call('flickr.photosets.comments.addComment', $params, true);
		return $this->response->comment;
	}

	/**
	 * photosets_comments_delete_comment
	 * 
	 * @param integer $comment_id
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function photosets_comments_delete_comment($comment_id)
	{
		$this->auth('write')->api_call('flickr.photosets.comments.deleteComment', array('comment_id' => $comment_id), true);
		return $this->response;
	}

	/**
	 * photosets_comments_edit_comment
	 * 
	 * @param integer $comment_id
	 * @param string $text
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function photosets_comments_edit_comment($comment_id, $text)
	{
		$params = array
		(
			'comment_id'	=> $comment_id,
			'comment_text'	=> $text
		);

		$this->auth('write')->api_call('flickr.photosets.comments.editComment', $params, true);
		return $this->response;
	}

	/**
	 * photosets_comments_get_list
	 * 
	 * @param integer $photoset_id
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function photosets_comments_get_list($photoset_id)
	{
		$this->api_call('flickr.photosets.comments.getList', array('photoset_id' => $photoset_id));
		return $this->response->comments;
	}

	/**
	 * places_find
	 * 
	 * @param string $query
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function places_find($query)
	{
		$this->api_call('flickr.places.find', array('query' => $query));
		return $this->response->places;
	}

	/**
	 * places_find_by_lat_lon
	 * 
	 * @param integer $lat
	 * @param integer $lon
	 * @param string $accuracy
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function places_find_by_lat_lon($lat, $lon, $accuracy = null)
	{
		$params = array
		(
			'lat'		=> $lat,
			'lon'		=> $lon,
			'accuracy'	=> $accuracy
		);

		$this->api_call('flickr.places.findByLatLon', $params);
		return $this->response->places;
	}

	/**
	 * places_resolve_place_id
	 * 
	 * @param integer $place_id
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function places_resolve_place_id($place_id)
	{
		$this->api_call('flickr.places.resolvePlaceId', array('place_id' => $place_id));
		return $this->response->location;
	}

	/**
	 * places_resolve_place_url
	 * 
	 * @param string $url
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function places_resolve_place_url($url)
	{
		$this->api_call('flickr.places.resolvePlaceURL', array('url' => $url));
		return $this->response->location;
	}

	/**
	 * prefs_get_content_type
	 * 
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function prefs_get_content_type()
	{
		$this->auth('read')->api_call('flickr.prefs.getContentType');
		return $this->response->person;
	}

	/**
	 * prefs_get_hidden
	 * 
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function prefs_get_hidden()
	{
		$this->auth('read')->api_call('flickr.prefs.getHidden');
		return $this->response->person;
	}

	/**
	 * prefs_get_geo_perms
	 * 
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function prefs_get_geo_perms()
	{
		$this->auth('read')->api_call('flickr.prefs.getGeoPerms');
		return $this->response->person;
	}

	/**
	 * prefs_get_privacy
	 * 
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function prefs_get_privacy()
	{
		$this->auth('read')->api_call('flickr.prefs.getPrivacy');
		return $this->response->person;
	}

	/**
	 * prefs_get_safety_level
	 * 
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function prefs_get_safety_level()
	{
		$this->auth('read')->api_call('flickr.prefs.getSafetyLevel');
		return $this->response->person;
	}

	/**
	 * reflection_get_method_info
	 * 
	 * @param string $method
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function reflection_get_method_info($method)
	{
		$this->api_call('flickr.reflection.getMethodInfo', array('method_name' => $method));
		return $this->response;
	}

	/**
	 * reflection_get_methods
	 * 
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function reflection_get_methods()
	{
		$this->api_call('flickr.reflection.getMethods');
		return $this->response->methods;
	}

	/**
	 * tags_get_clusters
	 * 
	 * @param string $tag
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function tags_get_clusters($tag)
	{
		$this->api_call('flickr.tags.getClusters', array('tag' => $tag));
		return $this->response->clusters;
	}

	/**
	 * tags_get_hot_list
	 * 
	 * @param string $period
	 * @param integer $count
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function tags_get_hot_list($period = 'day', $count = 20)
	{
		$params = array
		(
			'period' => $period,
			'count'	 => $count
		);

		$this->api_call('flickr.tags.getHotList', $params);
		return $this->response->hottags;
	}

	/**
	 * tags_get_list_photo
	 * 
	 * @param integer $photo_id
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function tags_get_list_photo($photo_id)
	{
		$this->api_call('flickr.tags.getListPhoto', array('photo_id' => $photo_id));
		return $this->response->photo->tags;
	}

	/**
	 * tags_get_list_user
	 * 
	 * @param integer $user_id
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function tags_get_list_user($user_id = null)
	{
		$this->api_call('flickr.tags.getListUser', array('user_id' => $user_id));
		return $this->response->who->tags;
	}

	/**
	 * tags_get_list_user_popular
	 * 
	 * @param integer $user_id
	 * @param integer $count
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function tags_get_list_user_popular($user_id = null, $count = 10)
	{
		$params = array
		(
			'user_id'	=> $user_id,
			'count'		=> $count
		);

		$this->api_call('flickr.tags.getListUserPopular', $params);
		return $this->response->who->tags;
	}

	/**
	 * tags_get_list_user_raw
	 * 
	 * @param string $tag
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function tags_get_list_user_raw($tag)
	{
		$this->api_call('flickr.tags.getListUserRaw', array('tag' => $tag));
		return $this->response->who->tags;
	}

	/**
	 * tags_get_related
	 * 
	 * @param string $tag
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function tags_get_related($tag)
	{
		$this->api_call('flickr.tags.getRelated', array('tag' => $tag));
		return $this->response->tags;
	}

	/**
	 * test_echo
	 * 
	 * @param array $params
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function test_echo($params = array())
	{
		$this->api_call('flickr.test.echo', $params);
		return $this->response;
	}

	/**
	 * test_login
	 * 
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function test_login()
	{
		$this->auth('read')->api_call('flickr.test.login');
		return $this->response->user;
	}

	/**
	 * test_null
	 * 
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function test_null()
	{
		$this->auth('read')->api_call('flickr.test.null');
		return $this->response;
	}

	/**
	 * urls_get_group
	 * 
	 * @param string $id
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function urls_get_group($id)
	{
		$this->api_call('flickr.urls.getGroup', array('group_id' => $id), true);
		return $this->response->group;
	}

	/**
	 * urls_get_user_photos
	 * 
	 * @param string $id
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function urls_get_user_photos($id = null)
	{
		$this->api_call('flickr.urls.getUserPhotos', array('user_id' => $id), true);
		return $this->response->user;
	}

	/**
	 * urls_get_user_profile
	 * 
	 * @param string $id
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function urls_get_user_profile($id = null)
	{
		$this->api_call('flickr.urls.getUserProfile', array('user_id' => $id), true);
		return $this->response->user;
	}

	/**
	 * urls_lookup_group
	 * 
	 * @param sring $url
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function urls_lookup_group($url)
	{
		$this->api_call('flickr.urls.lookupGroup', array('url' => $url), true);
		return $this->response->group;
	}

	/**
	 * urls_lookup_user
	 * 
	 * @param string $url
	 * @return object SimpleXMLElement Object
	 * @access public
	 * 
	 */
	public function urls_lookup_user($url)
	{
		$this->api_call('flickr.urls.lookupUser', array('url' => $url), true);
		return $this->response->user;
	}

	/**
	 * auth_check_token
	 *
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function auth_check_token()
	{
		$params = array();

		if ($token = $this->auth_get_token() and $token !== '')
			$params = array('token' => $token);

		$this->api_call('flickr.auth.checkToken', $params);
		return $this->response->auth;
	}

	/**
	 * auth_get_frob
	 *
	 * @return string
	 * @access public
	 *
	 */
	public function auth_get_frob()
	{
		$this->api_call('flickr.auth.getFrob', '', true);
		return (string) $this->response->frob;
	}

	/**
	 * auth_get_full_token
	 *
	 * @param string $token
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function auth_get_full_token($token)
	{
		$this->api_call('flickr.auth.getFullToken', array('mini_token' => $token), true);
		return $this->response->auth;
	}

	/**
	 * auth_get_token
	 *
	 * @return string
	 * @access public
	 *
	 */
	public function auth_get_token()
	{
		if ( ! ($frob = input::instance()->get('frob')))
			return false;

		$this->api_call('flickr.auth.getToken', array('frob' => $frob));
		Session::instance()->set('flickr_auth_token', (string) $this->response->auth->token);

		return Session::instance()->get('flickr_auth_token');
	}

	/**
	 * upload
	 * 
	 * @param string $photo
	 * @param string $title
	 * @param string $description
	 * @param mixed $tags
	 * @param boolean $is_public
	 * @param boolean $is_friend
	 * @param boolean $is_family
	 * @return object SimpleXMLElement Object
	 * @access public
	 *
	 */
	public function upload($photo, $title = null, $description = null, $tags = null, $is_public = null, $is_friend = null, $is_family = null)
	{
		if ( ! file_exists($photo) or ! is_readable($photo))
			throw new Kohana_User_Exception('Flickr Driver', Kohana::lang('service.file_error', $photo));

		if (is_array($tags))
		{
			$tags = '"' . implode('" "', $tags) . '"';
		}
		elseif ($tags)
		{
			$tags = (string) $tags;
		}

		$params = array
		(
			'title'			=> $title,
			'description'	=> $desc,
			'tags'			=> $tags,
			'is_public'		=> (int) $is_public,
			'is_friend'		=> (int) $is_riends,
			'is_family'		=> (int) $is_family
		);
		
		ksort($params);
		$signing = '';
		foreach($params as $key => $value)
			$signing .= $key . $value;

		$params['api_sig'] = md5($this->secret . $signing);
		$params['photo'] = '@' . $photo;
		$this->api_url = 'http://flickr.com/services/upload/';

		$this->auth('write')->api_call('', $params, true);
		return $this->response->photoid;
	}

	/**
	 * auth
	 *
	 * @param string $perms
	 * @return object
	 * @access public
	 *
	 */
	public function auth($perms = "read")
	{
		if ( ! Session::instance()->get('flickr_auth_token') and ! input::instance()->get('frob'))
		{
			url::redirect("http://flickr.com/services/auth/?".self::sign_params($this->secret, array("api_key" => $this->api_key,  "perms" => $perms)));
		}
		else
		{
			if ( ! $this->auth_check_token())
			{
				Session::instance()->delete('flickr_auth_token');
				$this->auth($perms);
			}
		}
		
		return $this;
	}

	/**
	 * photo_url
	 * 
	 * @param string $photo
	 * @param string size
	 * @return string
	 * @access public
	 * 
	 */
	public function photo_url($photo, $size = "Medium")
	{
		$sizes = array
		(
			"square"	=> "_s",
			"thumbnail" => "_t",
			"small"		=> "_m",
			"medium"	=> "",
			"large"		=> "_b",
			"original"	=> "_o"
		);

		$size = strtolower($size);
	
		if ( ! array_key_exists($size, $sizes))
			$size = "medium";

		if ($size == "original")
		{
			$url = "http://farm" . $photo['farm'] . ".static.flickr.com/" . $photo['server'] . "/" . $photo['id'] . "_" . $photo['originalsecret'] . "_o" . "." . $photo['originalformat'];
		}
		else
		{
			$url = "http://farm" . $photo['farm'] . ".static.flickr.com/" . $photo['server'] . "/" . $photo['id'] . "_" . $photo['secret'] . $sizes[$size] . ".jpg";
		}

		return $url;
	}

	/**
	 * api_call
	 * 
	 * @param string $api_url
	 * @param array $params
	 * @param boolean $post
	 * @return void
	 * @access protected
	 * 
	 */
	protected function api_call($api_url, $params = array(), $post = false)
	{
		$params = array_merge(array('method' => $api_url, 'api_key' => $this->api_key), $params);

		if ($token = Session::instance()->get('flickr_auth_token'))
			$params = array_merge($params, array('auth_token' => $token));

		if ( ! empty($this->secret))
			$params = self::sign_params($this->secret, $params);
		
		if ($post === true)
			$this->post();

		if ( ! ($result = parent::api_call($params, false)))
			throw new Kohana_User_Exception('Flickr Driver', Kohana::lang('service.invalid_response', $this->last_api_call(), $this->last_status_code()));
		
		$xml = simplexml_load_string($result);
		
		if (false === $xml)
			throw new Kohana_User_Exception('Flickr Driver', Kohana::lang('service.xml_parse_error'));
		
		if ( (string) $xml['stat'] !== 'ok')
			throw new Kohana_User_Exception('Flickr Driver', Kohana::lang('service.response_error', (string) $xml->err['msg'], $this->last_api_call()));
		
		$this->response = $xml;
	}

	/**
	 * sign_params
	 * 
	 * @param string $secret
	 * @param array $args
	 * @return string
	 * @access protected
	 * 
	 */
	protected static function sign_params($secret, $args)
	{
		$a = '';
		$v = array();
		ksort($args);
		foreach($args as $k => $val)
		{
			$a .= $k . $val;
			$v[] = $k . '=' . urlencode($val);
		}
		$v[] = 'api_sig=' . md5($secret . $a);

		return implode('&', $v);
	}

} //End Flickr Driver